package com.sansecy.android.simplevideo;

import android.content.Context;
import android.graphics.Color;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.Surface;
import android.view.TextureView;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.IOException;

/**
 * 项目名称：VideoTest
 * 类 名 称：HtdSimpleVideoView
 * 类 描 述：HtdSimpleVideoView
 * 创建时间：2019-11-15 15:30
 * 创 建 人：sansecy
 */
public class SimpleVideoView extends FrameLayout implements Player, TextureView.SurfaceTextureListener {
    private SurfaceTexture mSurfaceTexture;
    private VideoTextureView mTargetView;
    private static final String TAG = "HtdSimpleVideoView-App";
    private MediaPlayer mMediaPlayer;
    private MediaPlayer.OnPreparedListener mOnPreparedListener;
    private MediaPlayer.OnCompletionListener mOnCompletionListener;
    private MediaPlayer.OnErrorListener mOnErrorListener;
    private MediaPlayer.OnInfoListener mOnInfoListener;
    private MediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener;
    private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener;
    private MediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener;

    private int mTargetState = STATE_IDLE;
    private int mCurrentState = STATE_IDLE;

    private static final int STATE_ERROR = -1;
    private static final int STATE_IDLE = 0;
    private static final int STATE_PREPARING = 1;
    private static final int STATE_PREPARED = 2;
    private static final int STATE_PLAYING = 3;
    private static final int STATE_PAUSED = 4;
    private static final int STATE_PLAYBACK_COMPLETED = 5;

    private int mBufferingPercent = 0;
    private boolean mLooping = false;
    private String mUrl;
    private Uri mUri;
    private VideoTextureView mTextureView;
    private TextView textView;
    private long currentedTimeMillis;

    public SimpleVideoView(@NonNull Context context) {
        this(context, null);
    }

    public SimpleVideoView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setBackgroundColor(Color.BLACK);
        mTargetView = new VideoTextureView(getContext());
        mTargetView.setSurfaceTextureListener(this);
        LayoutParams params = new LayoutParams(-1, -1);
        params.gravity = Gravity.CENTER;
        addView(mTargetView, params);

        textView = new TextView(getContext());
        textView.setBackgroundColor(Color.WHITE);
        textView.setTextSize(16);
        LayoutParams params1 = new LayoutParams(-2, -2);
        params1.gravity = Gravity.END | Gravity.BOTTOM;
        textView.setTextColor(Color.RED);
        addView(textView, params1);
    }

    public void loadUrl(String url) {
        mUrl = url;
        mUri = null;
    }

    public void loadUri(Uri uri) {
        mUri = uri;
        mUrl = null;
    }

    public void openVideo() {
//        if (mMediaPlayer == null) {
//            mMediaPlayer = new MediaPlayer();
//        }
//        mMediaPlayer.reset();
        try {
            mMediaPlayer = new MediaPlayer();
            if (mUrl != null) {
                mMediaPlayer.setDataSource(mUrl);
            } else {
                mMediaPlayer.setDataSource(getContext(), mUri);
            }
            mMediaPlayer.setScreenOnWhilePlaying(true);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mMediaPlayer.setLooping(mLooping);
            Log.d(TAG, "openVideo() called mLooping:" + mLooping);
            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
            mMediaPlayer.setOnPreparedListener(mPreparedListener);
            mMediaPlayer.setOnCompletionListener(mCompletionListener);
            mMediaPlayer.setOnErrorListener(mErrorListener);
            mMediaPlayer.setOnInfoListener(mInfoListener);
            mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
            if (mSurfaceTexture != null) {
                mMediaPlayer.setSurface(new Surface(mSurfaceTexture));
            }
            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
            mMediaPlayer.prepareAsync();
            mCurrentState = STATE_PREPARING;
            Log.d(TAG, "openVideo: 正在准备");

        } catch (IOException | IllegalArgumentException | SecurityException | IllegalStateException e) {
            e.printStackTrace();
            Log.d(TAG, "openVideo: 准备出错");
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
        }
    }

    public void setLooping(boolean looping) {
        Log.d(TAG, "setLooping() called with: looping = [" + looping + "]");
        mLooping = looping;
        if (mMediaPlayer != null) {
            mMediaPlayer.setLooping(looping);
        }
    }

    public void stopPlayback() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            Log.d(TAG, "stopPlayback: 已停止播放");
            mCurrentState = STATE_IDLE;
            mTargetState = STATE_IDLE;
//            mAudioManager.abandonAudioFocus(null);
        }
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        if (mSurfaceTexture == null) {
            mSurfaceTexture = surface;
        } else {
            mTargetView.setSurfaceTexture(mSurfaceTexture);
        }
        if (mMediaPlayer != null) {
            mMediaPlayer.setSurface(new Surface(mSurfaceTexture));
        }
        Log.d(TAG, "onSurfaceTextureAvailable() called with: surface = [" + surface + "], width = [" + width + "], height = [" + height + "]");
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        Log.d(TAG, "onSurfaceTextureSizeChanged() called with: surface = [" + surface + "], width = [" + width + "], height = [" + height + "]");
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }
    int fps;

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
//        Log.d(TAG, "onSurfaceTextureUpdated() called with: surface = [" + surface + "]");
        boolean rest = false;
        if (System.currentTimeMillis() - currentedTimeMillis > 1000) {
            textView.setText(String.valueOf(fps));
            fps = 0;
            currentedTimeMillis = System.currentTimeMillis();
            rest = true;
        }
        if (!rest) {
            fps++;
        }
    }

    private void release(boolean cleartargetstate) {
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
            Log.d(TAG, "release: 已释放");
            mCurrentState = STATE_IDLE;
            //todo 处理音频焦点
//            if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
//                mAudioManager.abandonAudioFocus(null);
//            }
        }
    }

    public void start() {
        if (isInPlaybackState()) {
            if (mMediaPlayer != null) {
                mMediaPlayer.start();
                Log.d(TAG, "start: 正在播放");
                mCurrentState = STATE_PLAYING;
            }
        }
        Log.d(this.getClass().getSimpleName() + "-App", "start() called");
        mTargetState = STATE_PLAYING;
    }

    @Override
    public void pause() {
        if (isInPlaybackState()) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                Log.d(TAG, "pause: 已暂停");
                mCurrentState = STATE_PAUSED;
            }
        }
        mTargetState = STATE_PAUSED;
    }

    public boolean isInPlaybackState() {
        Log.d(TAG, "isInPlaybackState: 当前状态 = " + mCurrentState);
        return (mMediaPlayer != null &&
                mCurrentState != STATE_ERROR &&
                mCurrentState != STATE_IDLE &&
                mCurrentState != STATE_PREPARING);
    }

    @Override
    public int getDuration() {
        if (!isInPlaybackState()) {
            return 0;
        }
        if (mMediaPlayer != null) {
            return mMediaPlayer.getDuration();
        }
        return 0;
    }

    @Override
    public int getCurrentPosition() {
        if (!isInPlaybackState()) {
            return 0;
        }
        if (mMediaPlayer != null) {
            return mMediaPlayer.getCurrentPosition();
        }
        return 0;
    }

    @Override
    public void seekTo(int pos) {
        if (mMediaPlayer != null) {
            mMediaPlayer.seekTo(pos);
        }
    }

    @Override
    public boolean isPlaying() {
        if (mMediaPlayer != null) {
            return mMediaPlayer.isPlaying();
        }
        return false;
    }

    @Override
    public int getBufferPercentage() {
        return mBufferingPercent;
    }

    public void release() {
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            Log.d(TAG, "release: 已释放");
            mCurrentState = STATE_IDLE;
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mIsReleaseOnDetached) {
            pause();
            release();
        }
    }

    /**
     * 标识是否拉伸视图
     */
    private boolean mIsStretchVideoDimension;

    /**
     * TextureView默认拉伸视图，设置此标识为true以拉伸视图，否则HtdSimpleVideoView将会保持视频为原视频尺寸
     *
     * @param stretchVideoDimension 设置此标识为true以拉伸视图
     */
    public void setStretchVideoDimension(boolean stretchVideoDimension) {
        mIsStretchVideoDimension = stretchVideoDimension;
    }

    private boolean mIsReleaseOnDetached;

    public void setReleaseWhenDetached(boolean releaseOnDetached) {
        mIsReleaseOnDetached = releaseOnDetached;
    }

    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
            Log.d(TAG, "onBufferingUpdate() called with: mp = [" + mp + "], percent = [" + percent + "]");
            mBufferingPercent = percent;
            if (mOnBufferingUpdateListener != null) {
                mOnBufferingUpdateListener.onBufferingUpdate(mp, percent);
            }
        }
    };

    private MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            Log.d(TAG, "onPrepared() called with: mp = [" + mp + "]");
            mCurrentState = STATE_PREPARED;
            if (mOnPreparedListener != null) {
                mOnPreparedListener.onPrepared(mp);
            }
            Log.d(this.getClass().getSimpleName() + "-App", ":onPrepared mTargetState == STATE_PLAYING" + mTargetState);
            if (mTargetState == STATE_PLAYING) {
                start();
            }
        }
    };

    MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
            if (mOnVideoSizeChangedListener != null) {
                mOnVideoSizeChangedListener.onVideoSizeChanged(mp, width, height);
            }
            Log.d(TAG, "onVideoSizeChanged() called with: mp = [" + mp + "], width = [" + width + "], height = [" + height + "]");
            mTargetView.setVideoWidthHeight(width, height);
        }
    };
    MediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new MediaPlayer.OnSeekCompleteListener() {

        @Override
        public void onSeekComplete(MediaPlayer mp) {
            Log.d(TAG, "onSeekComplete() called with: mp = [" + mp + "]");
            if (mOnSeekCompleteListener != null) {
                mOnSeekCompleteListener.onSeekComplete(mp);
            }
        }
    };

    private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
        public void onCompletion(MediaPlayer mp) {
            Log.d(TAG, "onCompletion() called with: mp = [" + mp + "]");
            mCurrentState = STATE_PLAYBACK_COMPLETED;
            mTargetState = STATE_PLAYBACK_COMPLETED;

            if (mOnCompletionListener != null) {
                mOnCompletionListener.onCompletion(mp);
            }
        }
    };
    private MediaPlayer.OnErrorListener mErrorListener = new MediaPlayer.OnErrorListener() {
        public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            Log.d(TAG, "onError() called with: mp = [" + mp + "], framework_err = [" + framework_err + "], impl_err = [" + impl_err + "]");
            if (mOnErrorListener != null) {
                return mOnErrorListener.onError(mp, framework_err, impl_err);
            }
            return true;
        }
    };
    private MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
            return mOnInfoListener != null && mOnInfoListener.onInfo(mp, what, extra);
        }
    };

    public void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener onSeekCompleteListener) {
        mOnSeekCompleteListener = onSeekCompleteListener;
    }

    public void setOnPreparedListener(MediaPlayer.OnPreparedListener onPreparedListener) {
        mOnPreparedListener = onPreparedListener;
    }

    public void setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener onVideoSizeChangedListener) {
        mOnVideoSizeChangedListener = onVideoSizeChangedListener;
    }

    public void setOnCompletionListener(MediaPlayer.OnCompletionListener onCompletionListener) {
        mOnCompletionListener = onCompletionListener;
    }

    public void setOnErrorListener(MediaPlayer.OnErrorListener onErrorListener) {
        mOnErrorListener = onErrorListener;
    }

    public void setOnInfoListener(MediaPlayer.OnInfoListener onInfoListener) {
        mOnInfoListener = onInfoListener;
    }

    public void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener) {
        mOnBufferingUpdateListener = onBufferingUpdateListener;
    }
}


